// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

module gfmul_128_16 (
	input  logic [127:0] a,
	input  logic [15:0]  b,
	output logic [143:0] out
	);

logic [142:0] pp[15:0];

assign pp[0]  = {15'd0,a & {128{b[0]}}};
assign pp[1]  = {14'd0,a & {128{b[1]}} , 1'b0};
assign pp[2]  = {13'd0,a & {128{b[2]}} , 2'b0};
assign pp[3]  = {12'd0,a & {128{b[3]}} , 3'b0};
assign pp[4]  = {11'd0,a & {128{b[4]}} , 4'b0};
assign pp[5]  = {10'd0,a & {128{b[5]}} , 5'b0};
assign pp[6]  = {9'd0 ,a & {128{b[6]}} , 6'b0};
assign pp[7]  = {8'd0 ,a & {128{b[7]}} , 7'b0};
assign pp[8]  = {7'd0 ,a & {128{b[8]}} , 8'b0};
assign pp[9]  = {6'd0 ,a & {128{b[9]}} , 9'b0};
assign pp[10] = {5'd0 ,a & {128{b[10]}}, 10'b0};
assign pp[11] = {4'd0 ,a & {128{b[11]}}, 11'b0};
assign pp[12] = {3'd0 ,a & {128{b[12]}}, 12'b0};
assign pp[13] = {2'd0 ,a & {128{b[13]}}, 13'b0};
assign pp[14] = {1'd0 ,a & {128{b[14]}}, 14'b0};
assign pp[15] = {a & {128{b[15]}}, 15'b0};

assign out = {1'b0, pp[0] ^ pp[1] ^ pp[2] ^ pp[3] ^ pp[4] ^ pp[5] ^ pp[6] ^ pp[7] ^ pp[8] ^ pp[9] ^ pp[10] ^ pp[11] ^ pp[12] ^ pp[13] ^ pp[14] ^ pp[15]}; 

endmodule

module gfmul_red_st (
	input [128:0] in,
	output [127:0] out
);

assign out = {in[127:8], in[7] ^ in[128], in[6:3], in[2] ^ in[128], in[1] ^ in[128], in[0] ^ in[128]};


endmodule

module ghash_red_32b (
	input [159:0] in,
	output [127:0] out
);

logic [127:0] pp[31:0];

gfmul_red_st st0 (in[159:31],pp[0]);

genvar i;

generate 

for (i=1; i<32; i++) begin: red_st 

gfmul_red_st st ({pp[i-1],in[31-i]},pp[i]);

end
endgenerate

assign out = pp[31];

endmodule

